/* spwd.c: 简化版本的 pwd  
 *  
 * 从当前目录开始，递归地  
 * 向上遍历到文件系统根目录，打印上层部分  
 * 然后打印当前部分  
 *  
 * 使用 readdir() 获取每个项的信息  
 *  
 * 修复了原始版本在根目录运行时打印空字符串的Bug，  
 * 以及修复引发的新Bug：当不在根目录时，路径前不会再多出一个斜杠。  
 **/  

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <dirent.h>  
#include <string.h>  
#include <unistd.h>  

ino_t get_inode(const char *);  
void printpathto(ino_t);  
void inum_to_name(ino_t, char *, int);  

int main()  
{  
    ino_t current_inode = get_inode(".");  
    ino_t parent_inode = get_inode("..");  

    if (current_inode == parent_inode) { /* 如果当前目录是根目录 */  
        printf("/");  
    }  
    else {  
        printpathto(current_inode);  
    }  

    putchar('\n');  /* 添加换行符 */  
    return 0;  
}  

/*  
 * printpathto: 打印到具有指定 inode 的对象的路径  
 * 类似递归方法，从当前目录向上遍历，直到根目录  
 */  
void printpathto(ino_t this_inode)  
{  
    ino_t parent_inode = get_inode("..");  /* 获取父目录的 inode */  

    if (parent_inode != this_inode) {  /* 如果当前目录不是根目录 */  
        char name[BUFSIZ];  

        /* 切换到父目录 */  
        if (chdir("..") != 0) {  
            perror("chdir");  
            exit(EXIT_FAILURE);  
        }  

        /* 获取当前目录的名称 */  
        inum_to_name(this_inode, name, BUFSIZ);  

        /* 获取父目录的 inode，并递归调用 */  
        ino_t my_inode = get_inode(".");  
        printpathto(my_inode);  

        /* 打印目录名称前加 '/' */  
        printf("/%s", name);  
    }  
    else {  
        /* 到达根目录时，不打印任何内容 */  
        /* 由主函数处理根目录的打印 */  
    }  
}  

/*  
 * inum_to_name: 在当前目录中查找具有指定 inode 的文件，并将其名称复制到 namebuf  
 */  
void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen)  
{  
    DIR *dir_ptr;                /* 目录指针 */  
    struct dirent *direntp;      /* 目录项指针 */  

    dir_ptr = opendir(".");      /* 打开当前目录 */  
    if (dir_ptr == NULL) {  
        perror(".");  
        exit(EXIT_FAILURE);  
    }  

    /* 遍历目录，查找匹配的 inode */  
    while ((direntp = readdir(dir_ptr)) != NULL) {  
        if (direntp->d_ino == inode_to_find) {  
            strncpy(namebuf, direntp->d_name, buflen - 1);  
            namebuf[buflen - 1] = '\0';  /* 确保以 null 结尾 */  
            closedir(dir_ptr);  
            return;  
        }  
    }  

    /* 如果未找到匹配的 inode，输出错误信息 */  
    fprintf(stderr, "错误：无法找到 inode %lu\n", (unsigned long)inode_to_find);  
    closedir(dir_ptr);  
    exit(EXIT_FAILURE);  
}  

/*  
 * get_inode: 返回指定文件的 inode 号  
 */  
ino_t get_inode(const char *fname)  
{  
    struct stat info;  

    if (stat(fname, &info) == -1) {  /* 获取文件状态 */  
        fprintf(stderr, "无法获取文件状态: ");  
        perror(fname);  
        exit(EXIT_FAILURE);  
    }  
    return info.st_ino;  /* 返回 inode 号 */  
}